package com.wangyadong.hobby.schedule.jobtask.linkedlist;

/**
 * <p>
 *
 * @author <714037465@qq.com>
 * @since 2018/8/158:46
 **/
public class LinkedPositionalList<E> implements PositionalList {
    private static class Node<E> implements Position {

        private E element;
        private Node<E> pre;
        private Node<E> next;

        /****return current element*****/
        @Override
        public E getElement() throws IllegalStateException {
            if (next == null)
                throw new IllegalStateException("position no longer value");
            return element;
        }

        /******build a Node with pre and next ****/
        Node(E e, Node<E> pre, Node<E> next) {
            element = e;
            this.pre = pre;
            this.next = next;
        }


        public void setElement(E element) {
            this.element = element;
        }

        public Node<E> getPre() {
            return pre;
        }

        public void setPre(Node<E> pre) {
            this.pre = pre;
        }

        public Node<E> getNext() {
            return next;
        }

        public void setNext(Node<E> next) {
            this.next = next;
        }
    }


    private Node<E> header;
    private Node<E> tail;
    private int size;

    public LinkedPositionalList() {
        header = new Node<>(null, null, null);
        tail = new Node<>(null, header, null);
        header.setNext(tail);
    }

    private Node validate(Position<E> position) throws IllegalArgumentException {
        if (!(position instanceof
                Node)) throw new IllegalArgumentException("...");
        Node<E> node = (Node<E>) position;
        if (node.getNext() == null) {
            throw new IllegalArgumentException("...");
        }
        return node;
    }


    private Position<E> position(Node<E> node) {
        if (node == header || node == tail) {
            return null;
        }
        return node;
    }


    private Position<E> addBetween(E e, Node<E> pre, Node<E> next) {
        Node node = new Node(e, pre, next);
        pre.setNext(node);
        next.setPre(node);
        size++;
        return node;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size() == 0;
    }

    @Override
    public Position first() {
        return position(header.getNext());
    }

    @Override
    public Position last() {
        return position(tail.getPre());
    }

    @Override
    public Position before(Position p) throws IllegalArgumentException {
        return position(validate(p).getPre());
    }

    @Override
    public Position after(Position p) throws IllegalArgumentException {
        return position(validate(p).getNext());
    }

    @Override
    public Position<E> addFirst(Object object) {
        return addBetween((E) object, header, header.getNext());
    }

    @Override
    public Position addLast(Object object) {
        return addBetween((E) object, tail, tail.getPre());
    }

    @Override
    public Position addBefore(Position p, Object object) {
        Node validate = validate(p);
        return addBetween((E) object, validate.getPre(), validate);
    }

    @Override
    public Position addAfter(Position p, Object object) {
        Node validate = validate(p);
        return addBetween((E) object, validate, validate.getNext());
    }

    @Override
    public Object set(Position p, Object object) {
        Node validate = validate(p);
        Object element = validate.getElement();
        validate.setElement(object);
        return element;
    }

    @Override
    public Object remove(Position p) throws IllegalArgumentException {

        Node validate = validate(p);

        Node pre = validate.getPre();
        Node next = validate.getNext();
        pre.setNext(next);
        Object element = validate.getElement();
        validate.setNext(null);
        validate.setPre(null);
        validate.setElement(null);
        size--;
        return element;
    }

    public static void main(String[] args) {
        LinkedPositionalList<Integer> list = new LinkedPositionalList();
//        list.addFirst(111);
//        list.addFirst(112);


        Position head = list.first();
        while (head != null) {
            System.out.println(head.getElement());
            head = list.after(head);
        }

    }
}
